﻿/*
 * modbusregs.hpp
 *
 *  Created on: 2019-4-12
 *      Author: work
 */

#ifndef _DM_PROTOCOL_MODBUSREGS_HPP_
#define _DM_PROTOCOL_MODBUSREGS_HPP_

#include <dm/export.hpp>

#ifndef DM_API_PROTOCOL
#define DM_API_PROTOCOL DM_API_IMPORT
#endif

#include <dm/protocol/framemodbus.hpp>
#include <vector>

namespace dm{
namespace protocol{

/**
 * Modbus寄存器管理器
 */
class DM_API_PROTOCOL CModbusRegs{
public:
	typedef CFrameModbus::EFunc fun_t;

	/**
	 * 寄存器分段
	 */
	class CSegment{
	public:
		CSegment(const dm::uint16& address,const dm::uint16& quantity,int dataLen);
		~CSegment();

		inline bool ifAddressed( const dm::uint16& address,const dm::uint16& quantity=1 )const{
			return address>=m_address && (address+quantity)<=(m_address+m_quantity);
		}

		inline const dm::uint16& address()const{
			return m_address;
		}

		inline const dm::uint16& quantity()const{
			return m_quantity;
		}

		inline const dm::uint8* data()const{
			return m_data;
		}

		inline dm::uint8* data(){
			return m_data;
		}

		inline const int& len()const{
			return m_len;
		}

		inline const bool& updated()const{
			return m_updated;
		}

		inline void setUpdated(){
			m_updated = true;
		}

		inline void clearUpdated(){
			m_updated = false;
		}

		bool asBit( const dm::uint16& address )const;

		inline const dm::uint8* data( const dm::uint16& address )const{
			return m_data + (address-m_address)*2;
		}

	private:
		dm::uint16 m_address;
		dm::uint16 m_quantity;
		dm::uint8* m_data;
		int m_len;
		bool m_updated;
	};

public:
	CModbusRegs();
	~CModbusRegs();

	/**
	 * 增加分段
	 * @param fun
	 * @param addr
	 * @param quantity
	 * @return
	 */
	bool addSegment( const fun_t& fun,const dm::uint16& addr,const dm::uint16& quantity );

	/**
	 * 复位当前分段指针
	 */
	void curReset();
	inline const fun_t& curFun()const{
		return m_curFun;
	}
	const CSegment* curSegment()const;

	/**
	 * 移动到下一个分段
	 * @return 是否成功
	 * - true 成功
	 * - false 指针溢出
	 */
	bool curNext();

	/**
	 * 清除更新标志
	 */
	void clearUpdate();

	/**
	 * 更新分段
	 * @param fun
	 * @param address
	 * @param quantity
	 * @param data
	 * @param len
	 * @return
	 */
	bool update( const fun_t& fun,const dm::uint16& address,const dm::uint16& quantity,const dm::uint8* data,const int& len );

	bool isUpdated()const;
	bool isUpdated( const fun_t& fun,const dm::uint16& address )const;

	bool ifAddressed( const fun_t& fun,const dm::uint16& address,const dm::uint16& quantity )const;

	dm::uint16 get( const fun_t& fun,const dm::uint16& address )const;

	dm::uint8 get01( const dm::uint16& address )const;
	dm::uint8 get02( const dm::uint16& address )const;
	const dm::uint8* get03( const dm::uint16& address )const;
	const dm::uint8* get04( const dm::uint16& address )const;

	inline dm::int16 get03Int16( const dm::uint16& address )const{
		return toInt16(get03(address));
	}

	inline dm::uint16 get03Uint16( const dm::uint16& address )const{
		return toUint16(get03(address));
	}

	inline dm::int32 get03Int32( const dm::uint16& address )const{
		return toInt32(get03(address));
	}

	inline dm::int32 get03Int32Inv( const dm::uint16& address )const{
		return toInt32Inv(get03(address));
	}

	inline dm::uint32 get03Uint32( const dm::uint16& address )const{
		return toUint32(get03(address));
	}

	inline dm::uint32 get03Uint32Inv( const dm::uint16& address )const{
		return toUint32Inv(get03(address));
	}

	inline dm::int64 get03Int64( const dm::uint16& address )const{
		return toInt64(get03(address));
	}

	inline dm::int64 get03Int64Inv( const dm::uint16& address )const{
		return toInt32Inv(get03(address));
	}

	inline dm::uint64 get03Uint64( const dm::uint16& address )const{
		return toUint64(get03(address));
	}

	inline dm::uint64 get03Uint64Inv( const dm::uint16& address )const{
		return toUint64Inv(get03(address));
	}

	inline dm::float32 get03Float32( const dm::uint16& address )const{
		return toFloat32(get03(address));
	}

	inline dm::float32 get03Float32Inv( const dm::uint16& address )const{
		return toFloat32Inv(get03(address));
	}

	inline dm::float64 get03Float64( const dm::uint16& address )const{
		return toFloat64(get03(address));
	}

	inline dm::float64 get03Float64Inv( const dm::uint16& address )const{
		return toFloat64Inv(get03(address));
	}

	inline dm::uint16 get03BcdUint16( const dm::uint16& address )const{
		return toBcdUint16(get03(address));
	}

	inline dm::uint32 get03BcdUint32( const dm::uint16& address )const{
		return toBcdUint32(get03(address));
	}

	inline dm::uint32 get03BcdUint32Inv( const dm::uint16& address )const{
		return toBcdUint32Inv(get03(address));
	}

	inline dm::uint64 get03BcdUint64( const dm::uint16& address )const{
		return toBcdUint64(get03(address));
	}

	inline dm::uint64 get03BcdUint64Inv( const dm::uint16& address )const{
		return toBcdUint64Inv(get03(address));
	}

	inline bool get03Bit( const dm::uint16& address,const int& bit )const{
		return bitCheck(get03(address),bit);
	}

	inline dm::int16 get04Int16( const dm::uint16& address )const{
		return toInt16(get04(address));
	}

	inline dm::uint16 get04Uint16( const dm::uint16& address )const{
		return *(get04(address));
	}

	inline dm::int32 get04Int32( const dm::uint16& address )const{
		return toInt32(get04(address));
	}

	inline dm::int32 get04Int32Inv( const dm::uint16& address )const{
		return toInt32Inv(get04(address));
	}

	inline dm::uint32 get04Uint32( const dm::uint16& address )const{
		return toUint32(get04(address));
	}

	inline dm::uint32 get04Uint32Inv( const dm::uint16& address )const{
		return toUint32Inv(get04(address));
	}

	inline dm::int64 get04Int64( const dm::uint16& address )const{
		return toInt64(get04(address));
	}

	inline dm::int64 get04Int64Inv( const dm::uint16& address )const{
		return toInt32Inv(get04(address));
	}

	inline dm::uint64 get04Uint64( const dm::uint16& address )const{
		return toUint64(get04(address));
	}

	inline dm::uint64 get04Uint64Inv( const dm::uint16& address )const{
		return toUint64Inv(get04(address));
	}

	inline dm::float32 get04Float32( const dm::uint16& address )const{
		return toFloat32(get04(address));
	}

	inline dm::float32 get04Float32Inv( const dm::uint16& address )const{
		return toFloat32Inv(get04(address));
	}

	inline dm::float64 get04Float64( const dm::uint16& address )const{
		return toFloat64(get04(address));
	}

	inline dm::float64 get04Float64Inv( const dm::uint16& address )const{
		return toFloat64Inv(get04(address));
	}

	inline dm::uint16 get04BcdUint16( const dm::uint16& address )const{
		return toBcdUint16(get04(address));
	}

	inline dm::uint32 get04BcdUint32( const dm::uint16& address )const{
		return toBcdUint32(get04(address));
	}

	inline dm::uint32 get04BcdUint32Inv( const dm::uint16& address )const{
		return toBcdUint32Inv(get04(address));
	}

	inline dm::uint64 get04BcdUint64( const dm::uint16& address )const{
		return toBcdUint64(get04(address));
	}

	inline dm::uint64 get04BcdUint64Inv( const dm::uint16& address )const{
		return toBcdUint64Inv(get04(address));
	}

	inline bool get04Bit( const dm::uint16& address,const int& bit )const{
		return bitCheck(get04(address),bit);
	}

	// 通用函数接口

	static dm::int16 toInt16( const dm::uint8* p );
	static dm::uint16 toUint16( const dm::uint8* p );

	static dm::int32 toInt32( const dm::uint8* p );
	static dm::int32 toInt32Inv( const dm::uint8* p );
	static dm::uint32 toUint32( const dm::uint8* p );
	static dm::uint32 toUint32Inv( const dm::uint8* p );

	static dm::int64 toInt64( const dm::uint8* p );
	static dm::int64 toInt64Inv( const dm::uint8* p );
	static dm::uint64 toUint64( const dm::uint8* p );
	static dm::uint64 toUint64Inv( const dm::uint8* p );

	static dm::float32 toFloat32( const dm::uint8* p );
	static dm::float32 toFloat32Inv( const dm::uint8* p );
	static dm::float64 toFloat64( const dm::uint8* p );
	static dm::float64 toFloat64Inv( const dm::uint8* p );

	static dm::uint16 toBcdUint16( const dm::uint8* p );

	static dm::uint32 toBcdUint32( const dm::uint8* p );
	static dm::uint32 toBcdUint32Inv( const dm::uint8* p );
	static dm::uint64 toBcdUint64( const dm::uint8* p );
	static dm::uint64 toBcdUint64Inv( const dm::uint8* p );

	static bool bitCheck( const dm::uint8* p,int bit );

	static void fromInt16( const dm::int16& v,dm::uint8* p );
	static void fromUint16( const dm::uint16& v,dm::uint8* p );

	static void fromInt32( const dm::int32& v,dm::uint8* p );
	static void fromInt32Inv( const dm::int32& v,dm::uint8* p );
	static void fromUint32( const dm::uint32& v,dm::uint8* p );
	static void fromUint32Inv( const dm::uint32& v,dm::uint8* p );

	static void fromInt64( const dm::int64& v,dm::uint8* p );
	static void fromInt64Inv( const dm::int64& v,dm::uint8* p );
	static void fromUint64( const dm::uint64& v,dm::uint8* p );
	static void fromUint64Inv( const dm::uint64& v,dm::uint8* p );

	static void fromFloat32( const dm::float32& v,dm::uint8* p );
	static void fromFloat32Inv( const dm::float32& v,dm::uint8* p );
	static void fromFloat64( const dm::float64& v,dm::uint8* p );
	static void fromFloat64Inv( const dm::float64& v,dm::uint8* p );

	static void fromBcdUint16( const dm::uint16& v,dm::uint8* p );

	static void fromBcdUint32( const dm::uint32& v,dm::uint8* p );
	static void fromBcdUint32Inv( const dm::uint32& v,dm::uint8* p );

	static void fromBcdUint64( const dm::uint64& v,dm::uint8* p );
	static void fromBcdUint64Inv( const dm::uint64& v,dm::uint8* p );

	static void bitClear( const int& bit,dm::uint8* p );
	static void bitSet( const int& bit,dm::uint8* p );

	static dm::uint16 combine( const int& bitOffset,const int& bitLen,const dm::uint16& v,dm::uint16 reg=0x0000 );

protected:
	CSegment* addressSegment( const fun_t& fun,const dm::uint16& address,const dm::uint16& quantity );
	const CSegment* addressSegment( const fun_t& fun,const dm::uint16& address,const dm::uint16& quantity )const;

private:
	std::vector<CSegment*> m_segments[4];

	fun_t m_curFun;
	int m_curSegIdx;
};

}
}

#endif /* DM_RUNTIME_INCLUDE_DM_PROTOCOL_MODBUSREGS_HPP_ */
